//
//  LALocationConvert.c
//  OutdoorAssistantApplication
//
//  Created by 周欢 on 2018/1/3.
//  Copyright © 2018年 Lolaage. All rights reserved.
//

//--------- 坐标转换 宏 ---------------
#define LAT_OFFSET_0(x,y) (-100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x)))
#define LAT_OFFSET_1 ((20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0)
#define LAT_OFFSET_2 ((20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0)
#define LAT_OFFSET_3 ((160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0)

#define LON_OFFSET_0(x,y) (300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x)))
#define LON_OFFSET_1 ((20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0)
#define LON_OFFSET_2 ((20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0)
#define LON_OFFSET_3 ((150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0)


#define jzA 6378245.0
#define jzEE 0.00669342162296594323



// --------  中国区域判定 宏 -----------
#define RANGE_LON_MAX 137.8347
#define RANGE_LON_MIN 72.004
#define RANGE_LAT_MAX 55.8271
#define RANGE_LAT_MIN 0.8293

#define kAreaBoundCount 20

#define kMaxLon 134.876434//136.000000000133//国内最小经度
#define kMinLon 73.215853//71.9999999998592//国内最大经度
#define kMaxLat 53.750273//55.0000000002516//国内最大纬度
#define kMinLat 18.159306//14.9999999999315//国内最小纬度
// jzA = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;


//矩形区域边界
typedef struct{

    double lonMin;
    double lonMax;
    double latMin;
    double latMax;

} AreaBound;

#include "LALocationConvert.h"
#include <math.h>

//把最大的那个区块（0）放在第一个元素位置，判断该点概率最大。【注】plg19 包含香港区域,和上面的3个香港区域位置不能调换，可以简化区域判断，效率更高
//{lonMin,lonMa,latMin,latMax}
static AreaBound area[kAreaBoundCount] = {{88.734071,124.227124,26.604447,42.040451},//plg0
    {108.558785,111.526139,18.159306,21.117283},//plg1
    {97.42702,120.000604,24.360947,25.316831},//plg2
    {124.207702,129.109392,39.419449,42.040451},//plg3
    {82.277709,91.180783,45.38443,49.413186},//plg4
    {79.849493,96.404386,42.040451,45.393686},//plg5
    {115.354579,134.876434,45.538683,49.321576},//plg6
    {110.493935,133.539703,42.910794,45.551873},//plg7
    {96.404386,131.371298,42.040451,42.919356},//plg8
    {116.19791,129.900792,49.321559,53.750273},//plg9
    {73.215853,88.754768,32.882022,42.040451},//plg10
    {78.285175,88.758581,30.623965,32.882596},//plg11
    {79.980905,88.760945,29.243377,30.636236},//plg12
    {85.061428,88.763423,27.78383,28.584525},//plg13
    {83.462535,88.762064,28.578448,29.252788},//plg14
    {97.428281,125.827971,25.316795,26.636776},//plg15
    {113.825922,114.445501,22.153153,22.442493},//香港    //plg16  香港区域最小 ，概率低，放最后
   // {113.947258,114.439346,22.441715,22.492956},//香港    //plg17
    {113.951258,114.439346,22.441715,22.492956},//香港    //plg17
    {114.100019,114.395993,22.492523,22.532833},//香港     //plg18
    {97.422741,118.734333,21.107914,24.373303}//plg19      plg19 包含香港区域,和上面的3个香港区域位置不能调换，可以简化区域判断，效率更高
};


/**
 *    @brief    判断一个 CLLocationCoordinate2D 是否在中国行政区范围内，将国内分为若干矩形判断，边界可能有误差
 *
 *
 *    @param     lat , lon    传入的经纬度（WGS-84）; HkTWinclude 是否包含香港、台湾、澳门，google地图不包含香港台湾澳门、高德地图包含
 *
 */



bool isCoordinateInChinaRegion(double lat, double lon, bool HkTWInclude, bool isGaoDeCoor)
{

    if (lat > kMaxLat || lat < kMinLat || lon > kMaxLon || lon < kMinLon)
        return false;

    for(int i = 0; i < kAreaBoundCount ;i++)
    {
        AreaBound rectangular = area[i];
        if (lat > rectangular.latMin && lat < rectangular.latMax)
        {
            if (lon > rectangular.lonMin && lon < rectangular.lonMax)
            {
                if (isGaoDeCoor) {
                    // 高德系地图，不需要排除香港区域
                    return true;
                } else {
                    if(HkTWInclude)//包含香港、台湾的话只要在任一区域则返回true
                        return true;
                    else //需要进一步判断
                    {
                        //i == 17  18  19 指的是香港区域，属于非国内区域
                        return (i == 16 || i == 17 || i == 18) ? false : true;
                    }
                }
            }
        }
    }

    return false;
}

bool isChinaAdministrativeRegionWithCoor(double lat, double lon, bool isGaoDeCoor)
{
    return isCoordinateInChinaRegion(lat,lon,false, isGaoDeCoor);
}

#pragma mark --------- 坐标转换基础方法 ------------------
double transformLatBdLon(double lat ,double lon)
{
    double x = lat;
    double y = lon;

    double ret = LAT_OFFSET_0(x, y);
    ret += LAT_OFFSET_1;
    ret += LAT_OFFSET_2;
    ret += LAT_OFFSET_3;
    return ret;
}



double transformLonBdLon(double lat ,double lon)
{
    double x = lat;
    double y = lon;
    double ret = LON_OFFSET_0(x, y);
    ret += LON_OFFSET_1;
    ret += LON_OFFSET_2;
    ret += LON_OFFSET_3;
    return ret;
}

//百度转 gcj
CLLocationCoordinate2D base_bd09ToGcj02(double bdLat, double bdLng)
{
    CLLocationCoordinate2D coordinate;

    double x_pi = M_PI * 3000.0 / 180.0;
    double x = bdLng - 0.0065, y = bdLat - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
    double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);
    coordinate.longitude = z * cos(theta);
    coordinate.latitude = z * sin(theta);

    return coordinate;
}


//gcj 转 百度
CLLocationCoordinate2D base_gcj02ToBd09(double gcjLat, double gcjLng)
{
    CLLocationCoordinate2D coordinate;

    double x_pi = M_PI * 3000.0 / 180.0;
    double x = gcjLng, y = gcjLat;
    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
    double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
    coordinate.longitude = z * cos(theta) + 0.0065;
    coordinate.latitude = z * sin(theta) + 0.006;

    return coordinate;
}



// wgs 转 国测局02
CLLocationCoordinate2D base_wgsToGcj02(double wgsLat, double wgsLng)
{
    CLLocationCoordinate2D coordinate;

    double dLat = transformLatBdLon((wgsLng - 105.0),(wgsLat - 35.0));
    double dLon = transformLonBdLon((wgsLng - 105.0),(wgsLat - 35.0));
    double radLat = wgsLat / 180.0 * M_PI;
    double magic = sin(radLat);
    magic = 1 - jzEE * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * M_PI);
    dLon = (dLon * 180.0) / (jzA / sqrtMagic * cos(radLat) * M_PI);
    coordinate.latitude = wgsLat + dLat;
    coordinate.longitude = wgsLng + dLon;

    return coordinate;
}

//国测局 转 wgs
CLLocationCoordinate2D base_gcj02ToWgs84(double gcj02Lat, double gcj02Lng)
{
    CLLocationCoordinate2D coordinate;
    CLLocationCoordinate2D gcCoordinate;

    gcCoordinate = base_wgsToGcj02(gcj02Lat, gcj02Lng);

    double dLon = gcCoordinate.longitude - gcj02Lng;
    double dLat = gcCoordinate.latitude - gcj02Lat;
    coordinate.latitude = gcj02Lat - dLat;
    coordinate.longitude = gcj02Lng - dLon;

    return coordinate;
}



#pragma mark----------- 坐标转换 接口方法 --------
/*
 * wgs 转 Gcj02
 */
CLLocationCoordinate2D cl_wgsToGcj02(double wgsLat, double wgsLon, bool isGaoDeCoor)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(wgsLat, wgsLon, isGaoDeCoor))
    {
        coordinate.latitude = wgsLat;
        coordinate.longitude = wgsLon;
        return coordinate;
    }

    return base_wgsToGcj02(wgsLat, wgsLon);
}

/*
 * Gcj02 转 wgs
 */
CLLocationCoordinate2D cl_gcj02ToWgs84(double gcj02Lat, double gcj02Lon, bool isGaoDeCoor)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(gcj02Lat, gcj02Lon, isGaoDeCoor))
    {
        coordinate.latitude = gcj02Lat;
        coordinate.longitude = gcj02Lon;
        return coordinate;
    }

    return base_gcj02ToWgs84(gcj02Lat, gcj02Lon);
}

/*
 * wgs 转 Bd09
 */
CLLocationCoordinate2D cl_wgs84ToBd09(double wgsLat,double wgsLon)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(wgsLat, wgsLon, false))
    {
        coordinate.latitude = wgsLat;
        coordinate.longitude = wgsLon;
        return coordinate;
    }

    coordinate = base_wgsToGcj02(wgsLat, wgsLon);

    return base_gcj02ToBd09(coordinate.latitude, coordinate.longitude);
}

/*
 * Gcj02 转 Bd09
 */
CLLocationCoordinate2D cl_gcj02ToBd09(double gcj02Lat, double gcj02Lon)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(gcj02Lat, gcj02Lon, false))
    {
        coordinate.latitude = gcj02Lat;
        coordinate.longitude = gcj02Lon;
        return coordinate;
    }

    return base_gcj02ToBd09(gcj02Lat, gcj02Lon);
}


/*
 * Bd09 转 Gcj02
 */
CLLocationCoordinate2D cl_bd09ToGcj02(double bdLat, double bdLon)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(bdLat, bdLon, false))
    {
        coordinate.latitude = bdLat;
        coordinate.longitude = bdLon;
        return coordinate;
    }

    return base_bd09ToGcj02(bdLat, bdLon);
}

/*
 * Bd09 转 wgs
 */
CLLocationCoordinate2D cl_bd09ToWgs84(double bdLat, double bdLon)
{
    CLLocationCoordinate2D coordinate;
    if (!isChinaAdministrativeRegionWithCoor(bdLat, bdLon, false))
    {
        coordinate.latitude = bdLat;
        coordinate.longitude = bdLon;
        return coordinate;
    }

    coordinate = base_bd09ToGcj02(bdLat, bdLon);

    return base_gcj02ToWgs84(coordinate.latitude, coordinate.longitude);
}








